package com.lfs.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.lfs.admin.dao.DataAnalysisTaskDao;
import com.lfs.admin.dao.DataUploadDao;
import com.lfs.admin.dao.DataUploadDetailDao;
import com.lfs.admin.dao.DataUploadImageDao;
import com.lfs.admin.enums.AnalysisStatusEnums;
import com.lfs.admin.enums.TaskStatusEnums;
import com.lfs.admin.manager.DataAnalysisTaskWebSocketHandler;
import com.lfs.admin.model.entity.dataPackage.*;
import com.lfs.admin.model.vo.dataPackage.DataPackageVo;
import com.lfs.admin.model.vo.dataPackage.DataUploadVo;
import com.lfs.admin.service.DataPackageService;
import com.lfs.admin.service.DataRepositoryService;
import com.lfs.admin.service.MinioService;
import com.lfs.admin.service.system.TokenService;
import com.lfs.base.enums.ImageTypeEnums;
import com.lfs.base.util.CollectionUtils;
import com.lfs.base.util.StringUtils;
import com.lfs.common.core.domain.entity.SysUser;
import com.lfs.common.core.domain.model.LoginUser;
import com.lfs.common.core.redis.RedisCache;
import com.lfs.common.utils.ServletUtils;
import com.lfs.dao.entity.PageBean;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Service
@RequiredArgsConstructor
public class DataPackageServiceImpl implements DataPackageService {

    private final Logger logger = LoggerFactory.getLogger(DataPackageServiceImpl.class);

    @Autowired
    private DataUploadDao dataUploadDao;

    @Autowired
    private DataUploadDetailDao dataUploadDetailDao;


    @Autowired
    private DataUploadImageDao dataUploadImageDao;

    @Autowired
    private DataAnalysisTaskDao dataAnalysisTaskDao;

    @Autowired
    private DataRepositoryService dataRepositoryService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private MinioService minioService;

    @Autowired
    private RedisCache redisCache;

    private final DataAnalysisTaskWebSocketHandler webSocketHandler;
    private final ExecutorService executor = Executors.newFixedThreadPool(5);

    private final Map<Long, ReentrantLock> taskLocks = new ConcurrentHashMap<>();

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${lfs.profile:/data}")
    private String tempDir;

    @Override
    public String analysisData(DataPackageVo dataPackageVo) {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysUser user = loginUser.getUser();
        String agtNo = StringUtils.isBlank(user.getUserName()) ? "error" : user.getUserName();
        DataAnalysisTaskEntity task = new DataAnalysisTaskEntity();
        task.setTaskName(dataPackageVo.getFileName());
        task.setTaskStatus(TaskStatusEnums.PENDING.getCode());
        dataAnalysisTaskDao.insertDataAnalysisTask(task);
        // 异步执行任务
        logger.info("启动分析任务，任务ID: {}, 文件: {}", task.getId(), dataPackageVo.getFileName());
        executor.submit(() -> {
            try {
                extractImagesFromZip(task.getId(), dataPackageVo.getFilePath(),
                        dataPackageVo.getFileName(), agtNo, dataPackageVo.getProductType(), dataPackageVo.getDataSize());
            } catch (Exception e) {
                logger.error("任务执行异常，任务ID: {}", task.getId(), e);
            }
        });
        redisCache.setCacheObject("taskId:" + task.getId(), task);
        return "成功";
    }

    @Override
    public PageBean<DataUploadEntity> queryDataUploadList(DataUploadVo dataUploadVo) {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysUser user = loginUser.getUser();
        String agtNo = StringUtils.isBlank(user.getUserName()) ? "error" : user.getUserName();
        dataUploadVo.setAgtNo(agtNo);
        List<DataUploadEntity> dataUploadEntityList = Lists.newArrayList();
        try {
            PageHelper.startPage(dataUploadVo.getCurrentPage(), dataUploadVo.getPageSize());
            dataUploadEntityList = dataUploadDao.queryDataUploadList(dataUploadVo);

        } catch (Exception e) {
            logger.error("查询上传数据包列表异常={}", e.getMessage(), e);
        }
        return new PageBean<DataUploadEntity>(dataUploadEntityList);
    }

    @Override
    public PageBean<DataUploadDetailEntity> getDataUploadDetailList(DataUploadVo dataUploadVo) {
        List<DataUploadDetailEntity> dataUploadDetailEntityList = Lists.newArrayList();
        try {
            PageHelper.startPage(dataUploadVo.getCurrentPage(), dataUploadVo.getPageSize());
            dataUploadDetailEntityList = dataUploadDetailDao.getDataUploadDetailList(dataUploadVo);

        } catch (Exception e) {
            e.printStackTrace();
        }
        dataUploadDetailEntityList.stream().forEach(dataUploadDetail -> {

        });
        return new PageBean<DataUploadDetailEntity>(dataUploadDetailEntityList);
    }

    @Override
    public int deleteData(Integer[] ids) {
        int result = dataUploadDao.deleteData(ids);
        for (Integer id : ids) {
            dataUploadDetailDao.deleteDataDetail(id);
            List<Integer> idLists = dataUploadDetailDao.getUploadDetailByUploadId(id);
            if (CollectionUtils.isNotEmpty(idLists)) {
                dataUploadImageDao.deleteUploadImageByDetailId(idLists);
            }
        }
        return result;
    }

    // 检查文件是否为图片
    private boolean isImage(String fileName) {
        // 简单检查文件扩展名来判断是否为图片
        String lowerCaseName = fileName.toLowerCase();
        return lowerCaseName.endsWith(".png") || lowerCaseName.endsWith(".jpg") || lowerCaseName.endsWith(".jpeg")
                || lowerCaseName.endsWith(".gif") || lowerCaseName.endsWith(".bmp");
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void extractImagesFromZip(Long taskId, String zipFilePath, String fileName, String agtNo, String productType, int dataSize) {
        ReentrantLock lock = taskLocks.computeIfAbsent(taskId, k -> new ReentrantLock());
        if (!lock.tryLock()) {
            logger.info("任务{}已有线程在处理，跳过执行", taskId);
            return; // 已经有线程在处理此任务
        }
        try {
            DataAnalysisTaskEntity dataAnalysisTaskEntity = dataAnalysisTaskDao.findDataTaskById(taskId);
            if (null != dataAnalysisTaskEntity) {
                if (dataAnalysisTaskEntity.getTaskStatus().equals(TaskStatusEnums.PROCESSING.getCode())) {
                    return; // 避免重复处理
                }

                dataAnalysisTaskEntity.setTaskStatus(TaskStatusEnums.PROCESSING.getCode());
                dataAnalysisTaskDao.updateDataAnalysisTask(dataAnalysisTaskEntity);
                webSocketHandler.sendUpdate(dataAnalysisTaskEntity.getId(), "PROCESSING");
                List<String> savedFilePaths = new ArrayList<>();
                AtomicInteger successCount = new AtomicInteger();
                AtomicInteger failCount = new AtomicInteger();
                List<DataUploadDetailEntity> dataUploadDetailEntityList = Lists.newArrayList();
                // 指定要查找的文件夹名称
                List<String> targetFolders = Arrays.asList(ImageTypeEnums.BASE_IMAGE.getDescription(), ImageTypeEnums.OPTION_IMAGE.getDescription(), ImageTypeEnums.DETAIL_IMAGE.getDescription());
                Map<String, Map<String, List<DataUploadImageEntity>>> productFolders = new ConcurrentHashMap<>();
                List<DataUploadImageEntity> uploadImageEntityList = Lists.newArrayList();
                StringBuilder errors = new StringBuilder();
                AtomicBoolean found = new AtomicBoolean(true);
                DataUploadEntity dataUploadEntity = DataUploadEntity.builder().
                        id(taskId.intValue()).
                        agtNo(agtNo).
                        fileName(fileName).
                        seriesName(fileName.substring(0, fileName.indexOf("."))).build();
                dataUploadDao.insertDataUpload(dataUploadEntity);

                DataRepositoryEntity dataRepositoryEntity = DataRepositoryEntity.builder()
                        .id(taskId.intValue())
                        .agtNo(agtNo)
                        .productType(productType)
                        .seriesName(fileName.substring(0, fileName.indexOf(".")))
                        .dataSize(dataSize)
                        .status(AnalysisStatusEnums.PROCESSING.getCode()).build();
                dataRepositoryService.insertRepositoryData(dataRepositoryEntity);

                try {
                    URL url = new URL(zipFilePath);
                    InputStream in = url.openStream();
                    ZipInputStream zis = new ZipInputStream(in);
                    // 递归查找并提取目标文件夹中的图片
                    findAndExtractImages(productFolders, zis, targetFolders, savedFilePaths, dataUploadEntity.getId(), "");

                    for (Map.Entry<String, Map<String, List<DataUploadImageEntity>>> entry : productFolders.entrySet()) {
                        DataUploadDetailEntity dataUploadDetailEntity = new DataUploadDetailEntity();
                        dataUploadDetailEntity.setDataUploadId(dataUploadEntity.getId());
                        dataUploadDetailEntity.setAgtNo(agtNo);
                        // 检查每个产品是否包含"主图"和"选项图"
                        String productName = entry.getKey();
                        Map<String, List<DataUploadImageEntity>> folders = entry.getValue();

                        // 检查是否缺少"主图"
                        if (!folders.containsKey(ImageTypeEnums.BASE_IMAGE.getDescription())) {
                            errors.append("产品【").append(productName).append("】没有相关图片,此产品不进行保存！（丢弃）具体信息为【主图】文件夹不存在\n");
                            found.set(false);
                            failCount.addAndGet(1);
                            dataUploadDetailEntity.setMessage(errors.toString());
                            dataUploadDetailEntity.setProductName(productName);
                            dataUploadDetailEntity.setStatus("0");
                            dataUploadDetailEntityList.add(dataUploadDetailEntity);
                            continue;
                        }

                        // 检查是否缺少"选项图"
                        if (!folders.containsKey(ImageTypeEnums.OPTION_IMAGE.getDescription())) {
                            errors.append("产品【").append(productName).append("】没有相关图片此产品不进行保存！（丢弃）具体信息为【选项图】文件夹不存在\n");
                            found.set(false);
                            failCount.addAndGet(1);
                            dataUploadDetailEntity.setMessage(errors.toString());
                            dataUploadDetailEntity.setProductName(productName);
                            dataUploadDetailEntity.setStatus("0");
                            dataUploadDetailEntityList.add(dataUploadDetailEntity);
                            continue;
                        }

                        // 检查是否包含"详情图"
                        if (!folders.containsKey(ImageTypeEnums.DETAIL_IMAGE.getDescription())) {
                            logger.info("{}没有详情图文件夹，但继续保存主图和选项图", productName);
                        }

                        dataUploadDetailEntity.setProductName(productName);
                        dataUploadDetailEntity.setStatus("1");
                        successCount.addAndGet(1);
                        dataUploadDetailEntityList.add(dataUploadDetailEntity);
                    }
                    if (found.get()) {
                        dataUploadEntity.setStatus("1");
                    } else {
                        dataUploadEntity.setStatus("0");
                    }
                    dataUploadDetailDao.insertDataUploadDetail(dataUploadDetailEntityList);
                    dataUploadEntity.setFailCount(failCount.get());
                    dataUploadEntity.setSuccessCount(successCount.get());
                    dataUploadDao.updateDataUpload(dataUploadEntity);

                    dataRepositoryEntity.setCount(successCount.get());
                    dataRepositoryEntity.setStatus(AnalysisStatusEnums.COMPLETED.getCode());
                    dataRepositoryService.updateRepository(dataRepositoryEntity);

                    // 更新产品图片上传明细实体
                    for (Map.Entry<String, Map<String, List<DataUploadImageEntity>>> entry : productFolders.entrySet()) {
                        for (Map.Entry<String, List<DataUploadImageEntity>> imageEntry : entry.getValue().entrySet()) {
                            List<DataUploadImageEntity> uploadImageEntities = imageEntry.getValue();
                            if (CollectionUtil.isNotEmpty(uploadImageEntities)) {
                                uploadImageEntities.forEach(image -> {
                                    int lastSlashIndex = image.getImageName().lastIndexOf("/");  // 找到最后一个 "/" 的位置
                                    int dotIndex = image.getImageName().lastIndexOf(".");        // 找到 "." 的位置
                                    String specName = image.getImageName().substring(lastSlashIndex + 1, dotIndex);  // 截取中间部分
                                    image.setSpecName(specName);
                                    Optional<DataUploadDetailEntity> detailOption = dataUploadDetailEntityList.stream().filter(detail -> detail.getDataUploadId() == image.getDetailId() && detail.getProductName().equals(entry.getKey())).findAny();
                                    if (detailOption.isPresent()) {
                                        image.setDetailId(detailOption.get().getId());
                                        image.setImageType(ImageTypeEnums.getLookCodeMap().get(imageEntry.getKey()));
                                    }
                                });
                            }
                            uploadImageEntityList.addAll(uploadImageEntities);
                        }
                    }
                    dataUploadImageDao.insertUploadImage(uploadImageEntityList);
                    dataAnalysisTaskEntity.setTaskStatus(TaskStatusEnums.COMPLETED.getCode());
                    dataAnalysisTaskEntity.setProgress(100);
                    dataAnalysisTaskDao.updateDataAnalysisTask(dataAnalysisTaskEntity);
//                    webSocketHandler.sendUpdate(dataAnalysisTaskEntity.getId(), dataAnalysisTaskEntity.getTaskStatus());
                } catch (IOException e) {
                    logger.error("Error processing ZIP file: {}", e.getMessage(), e);
                    dataAnalysisTaskEntity.setTaskStatus(TaskStatusEnums.FAILED.getCode());
                    dataAnalysisTaskDao.updateDataAnalysisTask(dataAnalysisTaskEntity);
//                    webSocketHandler.sendUpdate(dataAnalysisTaskEntity.getId(), "FAILED");
                }
            }
        } finally {
            lock.unlock();
            taskLocks.remove(taskId); // 添加这行
        }
    }

//    @Transactional(propagation = Propagation.REQUIRES_NEW)
//    public void restartTask(Long taskId) {
//        ReentrantLock lock = taskLocks.computeIfAbsent(taskId, k -> new ReentrantLock());
//        if (!lock.tryLock()) {
//            return; // 避免重复提交
//        }
//
//        try {
//            DataAnalysisTaskEntity dataAnalysisTaskEntity = dataAnalysisTaskDao.findDataTaskById(taskId);
//            if (dataAnalysisTaskEntity.getTaskStatus().equals(TaskStatusEnums.FAILED.getCode())) {
//                dataAnalysisTaskEntity.setTaskStatus(TaskStatusEnums.PENDING.getCode());
//                dataAnalysisTaskDao.updateDataAnalysisTask(dataAnalysisTaskEntity);
//                executor.submit(() -> extractImagesFromZip(task.getId()));
//            }
//        } finally {
//            lock.unlock();
//        }
//    }

    // 递归查找目标文件夹并记录产品名称
    private void findAndExtractImages(Map<String, Map<String, List<DataUploadImageEntity>>> folderMap, ZipInputStream zis,
                                      List<String> targetFolders, List<String> savedFilePaths, int dataUploadId, String currentProduct) throws IOException {
        ByteArrayOutputStream baos = null;
        InputStream in = null;
        ZipEntry zipEntry;
        String imageType = null;
        while ((zipEntry = zis.getNextEntry()) != null) {
            String entryName = zipEntry.getName();
            // 如果是文件夹，更新当前路径映射
            if (zipEntry.isDirectory()) {
                // 提取产品名称（即上一级文件夹名称）
                String parentFolder = getParentDirectoryForTargetFolders(entryName, targetFolders);
                if (StringUtils.isNotNull(parentFolder)) {
                    currentProduct = parentFolder;
                }
            } else if (isImage(entryName)) {
                baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                // 读取ZipEntry的内容到ByteArrayOutputStream
                while ((bytesRead = zis.read(buffer)) != -1) {
                    baos.write(buffer, 0, bytesRead);
                }
                in = new ByteArrayInputStream(baos.toByteArray());
                // 如果是图片文件，检查是否在目标文件夹中
                for (String folder : targetFolders) {
                    if (entryName.contains(folder + "/") && isImage(entryName)) {
                        // 保存图片并获取保存路径
                        String savedPath = null;
                        try {
                            savedPath = minioService.putObject(bucketName, entryName, in, baos.size(), "image/jpg");
                        } catch (Exception e) {
                            logger.error("图片上传minio服务异常={}", e.getMessage(), e);
                        }
                        // 创建本地文件路径
                        String localFilePath = tempDir + entryName;
                        File localFile = new File(localFilePath);

                        // 确保父目录存在
                        File parentDir = localFile.getParentFile();
                        if (!parentDir.exists()) {
                            parentDir.mkdirs();
                        }

                        // 保存图片到本地
                        try (FileOutputStream fos = new FileOutputStream(localFile)) {
                            fos.write(baos.toByteArray());
                        } catch (Exception e) {
                            logger.error("图片保存到本地异常={}", e.getMessage(), e);
                            continue;
                        }
                        // 保存图片上传记录到lfs_data_upload_image表
                        DataUploadImageEntity dataUploadImageEntity = DataUploadImageEntity.builder()
                                .imageName(entryName)
                                .imageUrl(savedPath)
                                .localPath(localFilePath)
                                .detailId(dataUploadId).build();
                        savedFilePaths.add(savedPath);
                        folderMap.computeIfAbsent(currentProduct, k -> new HashMap<>())
                                .computeIfAbsent(folder, k -> new ArrayList<>())
                                .add(dataUploadImageEntity);

                    }
                }
            }
            if (null != in) {
                in.close();
            }
            if (null != baos) {
                baos.close();
            }
            zis.closeEntry();
        }
    }

    /**
     * 获取目标文件夹（如"主图","选项图","详情图"）的上一级目录名称。
     *
     * @param path 要解析的路径字符串
     * @return 上一级目录的名称，如果没有找到目标文件夹则返回null
     */
    public String getParentDirectoryForTargetFolders(String path, List<String> targetFolders) {
        // 创建Path对象
        Path pathObj = Paths.get(path);

        // 遍历路径组件，查找目标文件夹
        for (int i = pathObj.getNameCount() - 1; i >= 0; i--) {
            Path current = pathObj.getName(i);
            if (isTargetFolder(current.toString(), targetFolders)) {
                // 找到目标文件夹，获取其父级目录名称
                if (i > 0) {
                    return pathObj.getName(i - 1).toString();
                } else {
                    return null; // 目标文件夹是根目录
                }
            }
        }

        // 如果没有找到目标文件夹，返回null
        return null;
    }

    /**
     * 检查当前文件夹是否为目标文件夹之一。
     *
     * @param folderName 文件夹名称
     * @return 如果是目标文件夹之一，则返回true，否则返回false
     */
    private boolean isTargetFolder(String folderName, List<String> targetFolders) {
        for (String target : targetFolders) {
            if (target.equals(folderName)) {
                return true;
            }
        }
        return false;
    }

}
